﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;

namespace LightCAD.Core
{
    public abstract class CptAttribute : Attribute 
    {
        public string Category;
        public List<string> SubCategorys;
        public CptAttribute(string category, string subCategorys)
        {
            this.Category = category;
            this.SubCategorys = subCategorys.split(",");
        }
        public abstract LcComponentDefinition GetBuiltinCpt(string subCategory);
       
    }
 
    /// <summary>
    /// 组件定义上的类型参数定义缓存，为后续编辑类型参数界面等功能做准备
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class CptTypeParamsDef<T> where T : LcComponentDefinition
    {
        public static ParameterSetDefinition ParamsDef;
    }
    public static class ComponentManager
    {
        private static Dictionary<string ,LcComponentDefinition> allComponents=new Dictionary<string, LcComponentDefinition> ();
        private static Dictionary<string,Dictionary<string,List< LcComponentDefinition>>> Components=new Dictionary<string, Dictionary<string, List<LcComponentDefinition>>>();
        public static void LoadCptBuiltinDefs() 
        {
            var assemblies = AppDomain.CurrentDomain.GetAssemblies();
            foreach (Assembly asm in assemblies)
            {
                var asmName = asm.GetName().Name;
                Debug.Assert(asmName != null, nameof(asmName) + " != null");

                //if (!LcRuntime.RegistAssemblies.Contains(asmName)) continue;
                if (asmName.StartsWith("System"))
                    continue;
                var types = asm.GetTypes();
                foreach (Type type in types)
                {
                    var cptAttr = type.GetCustomAttribute(typeof(CptAttribute)) as CptAttribute;
                    if (cptAttr == null) continue;
         
                    for (int i = 0; i < cptAttr.SubCategorys.Count; i++)
                    {
                        var def= cptAttr.GetBuiltinCpt(cptAttr.SubCategorys[i]);
                        if (def == null)
                            continue;
                        AddCptDefs(def);
                    }
                }
            }
        }
       
        public static T GetCptDef<T>(string category, string subCategory, string uuid) where T: LcComponentDefinition
        {
            return GetCptDefs(category, subCategory).Find(c => c.Uuid == uuid) as T;
        }
        public static void AddCptDefs(LcComponentDefinition componentDefinition)
        {
            if (componentDefinition == null)
                return;
            GetCptDefsOrigin(componentDefinition.Category, componentDefinition.SubCategory).Add(componentDefinition);
            allComponents.Add(componentDefinition.Uuid, componentDefinition);
        }
        public static T GetCptDef<T>( string uuid) where T : LcComponentDefinition
        {
            return GetCptDef(uuid) as T;
        }
        public static LcComponentDefinition GetCptDef(string uuid)
        {
            return allComponents.ContainsKey(uuid) ? allComponents[uuid] : null;
        }

        private static List<LcComponentDefinition> GetCptDefsOrigin(string category, string subCategory) 
        {
            if (!Components.ContainsKey(category))
                Components.Add(category, new Dictionary<string, List<LcComponentDefinition>>());
            var cateDefs = Components[category];
            if (!cateDefs.ContainsKey(subCategory))
                cateDefs.Add(subCategory, new List<LcComponentDefinition>());
            return cateDefs[subCategory];
        }
        public static List<LcComponentDefinition> GetCptDefs(string category, string subCategory)
        {
            return GetCptDefsOrigin(category,subCategory).ToList();
        }
        public static List<LcComponentDefinition> GetExternalCptDefs()
        {
            return allComponents.Values.Where(c => c.Name != "内置").ToList();
        }
    }
}